package gang.org.springframework.framework.core.io.support;

import gang.org.springframework.framework.core.io.GangResourcePatternResolver;
import gang.org.springframework.framework.io.GangFileSystemResource;
import gang.org.springframework.framework.io.GangResource;
import gang.org.springframework.framework.io.GangResourceLoader;
import gang.org.springframework.framework.io.GangUrlResource;
import gang.org.springframework.framework.util.GangAntPathMatcher;
import gang.org.springframework.framework.util.GangPathMatcher;
import gang.org.springframework.framework.util.GangStringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;

/**
 * @author gang.chen
 * @Date 2022/10/12 13:36
 */
public class GangPathMatchingResourcePatternResolver implements GangResourcePatternResolver {

    public GangPathMatcher getPathMatcher() {
        return this.pathMatcher;
    }

    private final GangPathMatcher pathMatcher = new GangAntPathMatcher();

    private final GangResourceLoader resourceLoader;


    @Override
    public ClassLoader getClassLoader() {
        return null;
    }

    @Override
    public GangResource getResource(String location) {

        if (location.startsWith(classpath_all_url_prefix)) {

            if (true){
                findPathMatchingResources(location);
            }else {
                //TODO
            }

        }else {
            //TODO
        }

        return null;
    }

    @Override
    public GangResource[] getResources(String locationPattern) {
        if (locationPattern.startsWith(classpath_all_url_prefix)) {
            if (getPathMatcher().isPattern(locationPattern.substring(classpath_all_url_prefix.length()))) {
                return findPathMatchingResources(locationPattern);
            }else {
                return findAllClassPathResources(locationPattern.substring(classpath_all_url_prefix.length()));
            }
        }else {
            //TODO
        }
        return null;
    }

    private GangResource[] findPathMatchingResources(String locationPattern) {

        String rootDirPath = determineRootDir(locationPattern);
        String subPattern = locationPattern.substring(rootDirPath.length());
        GangResource[] rootDirResources = getResources(rootDirPath);

        Set<GangResource> result = new LinkedHashSet<>(16);

        for (GangResource rootDirResource : rootDirResources) {

            rootDirResource = resolveRootDirResource(rootDirResource);

            URL rootDirUrl = rootDirResource.getURL();

            if (false){
                //TODO
            }

            if (false){
                //TODO
            }
            else if (false){
                //TODO
            }else {
                result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
            }
        }
        return result.toArray(new GangResource[0]);
    }


    public GangPathMatchingResourcePatternResolver(GangResourceLoader resourceLoader){
        this.resourceLoader = resourceLoader;
    }

    /**
     * 路径转换
     * 例如：-代表*
     *  转换后:"classpath*:gang/com/org/service/"
     *  转换前:"classpath*:gang/com/org/service/--/-.class"
     * */
    protected String determineRootDir(String location){

        int prefixedEnd = location.indexOf(":") + 1;
        int rootDirEnd = location.length();

        while (rootDirEnd > prefixedEnd && getPathMatcher().isPattern(location.substring(prefixedEnd, rootDirEnd))){

            rootDirEnd = location.lastIndexOf("/", rootDirEnd - 2) + 1;
        }

        if (rootDirEnd == 0){
            rootDirEnd = prefixedEnd;
        }
        return location.substring(0, rootDirEnd);
    }

    protected GangResource[] findAllClassPathResources(String location){
        String path = location;

        if (path.startsWith("/")) {
            path = path.substring(1);
        }

        Set<GangResource> result = doFindAllClassPathResources(path);

        return result.toArray(new GangResource[0]);
    }

    protected Set<GangResource> doFindAllClassPathResources(String path){

        Set<GangResource> result = new LinkedHashSet<>(16);

        ClassLoader classLoader = getClassLoader();

        try {

            //JDK原生处理
            Enumeration<URL> resourceUrl = classLoader != null? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
            while (resourceUrl.hasMoreElements()){
                /**
                 * URL对象属性值如下：
                 * protocol = "file"
                 * file = "/D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service/"
                 * path = "/D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service/"
                 * ...
                 * */
                URL url = resourceUrl.nextElement();
                result.add(convertClassLoaderURL(url));
            }

            if (false){
                //TODO
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    protected GangResource convertClassLoaderURL(URL url){
        return new GangUrlResource(url);
    }

    protected  GangResource resolveRootDirResource(GangResource original){
        return original;
    }

    protected Set<GangResource> doFindPathMatchingFileResources(GangResource rootDirResource, String subPattern){

        File rootDir;

        try{
            rootDir = rootDirResource.getFile();
        }
        catch (Exception e){
            return Collections.emptySet();
        }

        //TODO
        return doFindMatchingFileSystemResources(rootDir, subPattern);
    }

    protected Set<GangResource> doFindMatchingFileSystemResources(File rootDir, String subPattern){
        if (false){
            //TODO
        }

        Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);

        Set<GangResource> result = new LinkedHashSet<>(matchingFiles.size());

        for (File file : matchingFiles) {
            //TODO
            result.add(new GangFileSystemResource(file));
        }
        return result;
    }

    protected Set<File> retrieveMatchingFiles(File rootDir, String pattern){
        if (false){
            //TODO
        }

        if (false){
            //TODO
        }

        if (false){
            //TODO
        }

        /**
         * fullPattern = "D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service"
         * */
        String fullPattern = GangStringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");

        if (!pattern.startsWith("/")) {
            fullPattern += "/";
        }
        /**
         * fullPattern = "D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service/"
         * */
        //fullPattern = "D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service/**/*.Class"
        fullPattern = fullPattern + GangStringUtils.replace(pattern, File.separator, "/");
        Set<File> result = new LinkedHashSet<>(8);
        doRetrieveMatchingFiles(fullPattern, rootDir, result);
        return result;
    }

    private void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) {
        if (false){
            //TODO
        }

        for (File file : listDirectory(dir)) {

            //currPath = "D:/2022/source/gang-springboot/gang-springboot/target/classes/gang/com/org/service/ResourceA.class"
            String currPath = GangStringUtils.replace(file.getAbsolutePath(), File.separator, "/");

            if (false){
                //TODO
            }

            if (getPathMatcher().match(fullPattern, currPath)) {
                result.add(file);
            }

        }
    }

    /**
     * dir = "D:\2022\source\gang-springboot\gang-springboot\target\classes\gang\com\org\service"
     * */
    protected File[] listDirectory(File dir){
        File[] files = dir.listFiles();
        if (false){
            //TODO
        }
        Arrays.sort(files, Comparator.comparing(File::getName));
        return files;
    }


}
